package org.example.interceptor;

import com.alibaba.fastjson.JSONObject;
import org.apache.commons.lang3.StringUtils;
import org.example.handler.TenantCacheHolder;
import org.example.handler.TenantContextHolder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.web.servlet.HandlerInterceptor;
import org.springframework.web.servlet.ModelAndView;
import org.example.vo.TenantVo;

import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.io.IOException;

/**
 * @version V1.0
 * @description: 租户访问拦截解析处理抽象父类
 * @author: 宏伟数科-刘冬冬
 * @contact: QQ791156095
 * @date: 2020/3/8 20:42
 * @Copyright 该项目由宏伟数科版权所有，未经过允许的情况下，私自分享视频和源码属于违法行为。
 */
public  class TenantMarkParserInterceptor implements HandlerInterceptor {

    @Autowired
    protected StringRedisTemplate redisTemplate;

    @Override
    public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception {
        String requestType = request.getHeader("X-Requested-With");
        String url = request.getRequestURL().toString();
        String serverPort = request.getScheme() + "://" + request.getServerName() + ":" + request.getServerPort();
        String tenantDomain;
        if (url.startsWith(serverPort)) {
            tenantDomain = request.getServerName() + ":" + request.getServerPort();
        } else {
            tenantDomain = request.getServerName();
        }
        // 检查缓存是否存在当前租户
        TenantVo tenantVo = this.parserTenant(tenantDomain);
        if (tenantVo == null) {
            // 租户不存在异常
            tenantNotExist(tenantDomain, requestType, request, response);
            return false;
        }
        if (!checkTenant(tenantDomain, requestType, tenantVo, request, response)) {
            return false;
        }
        TenantContextHolder.setTenant(tenantVo);
        return true;
    }

    @Override
    public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception {

    }

    @Override
    public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception {
        TenantContextHolder.clear();
    }

    /**
     * 自定义租户检查
     * @param tenantDomain
     * @param requestType
     * @param request
     * @param response
     */
    public boolean checkTenant(String tenantDomain, String requestType, TenantVo tenantVo, HttpServletRequest request, HttpServletResponse response) {
        return true;
    }

    /**
     * 租户不存在异常处理
     * @param tenantDomain
     * @param requestType
     * @param request
     * @param response
     */
    public  void tenantNotExist(String tenantDomain, String requestType, HttpServletRequest request, HttpServletResponse response){
        try {
            response.sendError(404);
        } catch (IOException e) {
            e.printStackTrace();
        }
    }

    /**
     * 校验域名
     * @param domain
     */
    private TenantVo parserTenant(String domain) {
        String tenantKey = tenantDomain(domain);
        String tenantVoStr = null;
        // 查找本地缓存
        if (!TenantCacheHolder.getTenantLocalCache().containsKey(tenantKey)) {
            // 查找Redis缓存
            if (redisTemplate.opsForHash().hasKey(TenantCacheHolder.TENANT_KEY, tenantKey)) {
                tenantVoStr = (String) redisTemplate.opsForHash().get(TenantCacheHolder.TENANT_KEY, tenantKey);
                TenantCacheHolder.getTenantLocalCache().put(tenantKey, tenantVoStr);
            }
        } else {
            tenantVoStr = TenantCacheHolder.getTenantLocalCache().get(tenantKey);
        }
        if (StringUtils.isBlank(tenantVoStr)) {
            TenantCacheHolder.getTenantLocalCache().put(tenantKey, "");
            return null;
        }
        return JSONObject.parseObject(tenantVoStr, TenantVo.class);
    }

    private String tenantDomain(String domain) {
        return TenantCacheHolder.getTenantKey(domain);
    }

}
